package com.xscha.tableforge.service.impl;

import com.xscha.tableforge.constants.FieldType;
import com.xscha.tableforge.model.dto.RelationMetaDto;
import com.xscha.tableforge.model.entity.RelationMeta;
import com.xscha.tableforge.model.entity.RelationMapping;
import com.xscha.tableforge.repository.FieldMetaRepository;
import com.xscha.tableforge.repository.RelationMappingRepository;
import com.xscha.tableforge.repository.RelationMetaRepository;
import com.xscha.tableforge.repository.TableMetaRepository;
import com.xscha.tableforge.service.RelationMetaService;
import com.xscha.tableforge.utils.IdUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 关联字段元数据服务实现类
 */
@Service
public class RelationMetaServiceImpl implements RelationMetaService {

    private final RelationMetaRepository relationMetaRepository;
    private final RelationMappingRepository relationMappingRepository;
    private final FieldMetaRepository fieldMetaRepository;
    private final TableMetaRepository tableMetaRepository;

    @Autowired
    public RelationMetaServiceImpl(
            RelationMetaRepository relationMetaRepository,
            RelationMappingRepository relationMappingRepository,
            FieldMetaRepository fieldMetaRepository,
            TableMetaRepository tableMetaRepository) {
        this.relationMetaRepository = relationMetaRepository;
        this.relationMappingRepository = relationMappingRepository;
        this.fieldMetaRepository = fieldMetaRepository;
        this.tableMetaRepository = tableMetaRepository;
    }

    @Override
    public Optional<RelationMeta> findById(String id) {
        return relationMetaRepository.findById(id);
    }

    @Override
    public Optional<RelationMeta> findByFieldId(String fieldId) {
        return relationMetaRepository.findByFieldId(fieldId);
    }

    @Override
    public List<RelationMeta> findAllByTableId(String tableId) {
        return relationMetaRepository.findAllByTableId(tableId);
    }

    @Override
    @Transactional
    public RelationMeta createRelationMeta(RelationMetaDto relationMetaDto, String userId) {
        // 1. 验证目标表和字段是否存在
        tableMetaRepository.findById(relationMetaDto.getTargetTableId())
                .orElseThrow(() -> new RuntimeException("目标表不存在"));
        
        fieldMetaRepository.findById(relationMetaDto.getTargetFieldId())
                .orElseThrow(() -> new RuntimeException("目标字段不存在"));
        
        fieldMetaRepository.findById(relationMetaDto.getDisplayFieldId())
                .orElseThrow(() -> new RuntimeException("显示字段不存在"));
        
        // 2. 创建关联字段元数据
        RelationMeta relationMeta = new RelationMeta();
        relationMeta.setId(IdUtil.createRelationMetaId());
        relationMeta.setFieldId(relationMetaDto.getFieldId());
        relationMeta.setTargetTableId(relationMetaDto.getTargetTableId());
        relationMeta.setTargetFieldId(relationMetaDto.getTargetFieldId());
        relationMeta.setDisplayFieldId(relationMetaDto.getDisplayFieldId());
        relationMeta.setRelationType(relationMetaDto.getRelationType());
        relationMeta.setCascadeDelete(relationMetaDto.getCascadeDelete() != null ? relationMetaDto.getCascadeDelete() : false);
        relationMeta.setVersion(1);
        relationMeta.setCreatedTime(LocalDateTime.now());
        relationMeta.setCreatedBy(userId);
        
        return relationMetaRepository.save(relationMeta);
    }

    @Override
    @Transactional
    public RelationMeta updateRelationMeta(String id, RelationMetaDto relationMetaDto, String userId) {
        // 1. 查询关联字段元数据
        RelationMeta relationMeta = relationMetaRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("关联字段不存在"));
        
        // 2. 验证目标表和字段是否存在
        if (relationMetaDto.getTargetTableId() != null) {
            tableMetaRepository.findById(relationMetaDto.getTargetTableId())
                    .orElseThrow(() -> new RuntimeException("目标表不存在"));
            relationMeta.setTargetTableId(relationMetaDto.getTargetTableId());
        }
        
        if (relationMetaDto.getTargetFieldId() != null) {
            fieldMetaRepository.findById(relationMetaDto.getTargetFieldId())
                    .orElseThrow(() -> new RuntimeException("目标字段不存在"));
            relationMeta.setTargetFieldId(relationMetaDto.getTargetFieldId());
        }
        
        if (relationMetaDto.getDisplayFieldId() != null) {
            fieldMetaRepository.findById(relationMetaDto.getDisplayFieldId())
                    .orElseThrow(() -> new RuntimeException("显示字段不存在"));
            relationMeta.setDisplayFieldId(relationMetaDto.getDisplayFieldId());
        }
        
        // 3. 更新关联字段元数据
        if (relationMetaDto.getRelationType() != null) {
            relationMeta.setRelationType(relationMetaDto.getRelationType());
        }
        
        if (relationMetaDto.getCascadeDelete() != null) {
            relationMeta.setCascadeDelete(relationMetaDto.getCascadeDelete());
        }
        
        relationMeta.setVersion(relationMeta.getVersion() + 1);
        relationMeta.setLastModifiedTime(LocalDateTime.now());
        relationMeta.setLastModifiedBy(userId);
        
        return relationMetaRepository.update(relationMeta);
    }

    @Override
    @Transactional
    public void deleteRelationMeta(String id, String userId) {
        // 1. 查询关联字段元数据
        RelationMeta relationMeta = relationMetaRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("关联字段不存在"));
        
        // 2. 删除所有关联映射
        relationMappingRepository.deleteAllByRelationFieldId(relationMeta.getFieldId());
        
        // 3. 删除关联字段元数据
        relationMetaRepository.delete(id);
    }

    @Override
    @Transactional
    public void createRelation(String relationFieldId, String sourceRecordId, String targetRecordId, String userId) {
        // 1. 查询关联字段元数据
        RelationMeta relationMeta = relationMetaRepository.findByFieldId(relationFieldId)
                .orElseThrow(() -> new RuntimeException("关联字段不存在"));
        
        // 2. 检查关系类型，如果是一对一或多对一，需要先删除现有关联
        String relationType = relationMeta.getRelationType();
        if (FieldType.RELATION_ONE_TO_ONE.getCode().equals(relationType) || 
            FieldType.RELATION_MANY_TO_ONE.getCode().equals(relationType)) {
            relationMappingRepository.deleteAllByRelationFieldIdAndSourceRecordId(relationFieldId, sourceRecordId);
        }
        
        // 3. 创建关联映射
        RelationMapping relationMapping = new RelationMapping();
        relationMapping.setId(IdUtil.createRelationMetaId());
        relationMapping.setRelationFieldId(relationFieldId);
        relationMapping.setSourceRecordId(sourceRecordId);
        relationMapping.setTargetRecordId(targetRecordId);
        
        relationMappingRepository.save(relationMapping);
    }

    @Override
    @Transactional
    public void createRelations(String relationFieldId, String sourceRecordId, List<String> targetRecordIds, String userId) {
        // 1. 查询关联字段元数据
        RelationMeta relationMeta = relationMetaRepository.findByFieldId(relationFieldId)
                .orElseThrow(() -> new RuntimeException("关联字段不存在"));
        
        // 2. 检查关系类型，如果是一对一或多对一，只保留第一个目标记录
        String relationType = relationMeta.getRelationType();
        if (FieldType.RELATION_ONE_TO_ONE.getCode().equals(relationType) || 
            FieldType.RELATION_MANY_TO_ONE.getCode().equals(relationType)) {
            if (!targetRecordIds.isEmpty()) {
                relationMappingRepository.deleteAllByRelationFieldIdAndSourceRecordId(relationFieldId, sourceRecordId);
                createRelation(relationFieldId, sourceRecordId, targetRecordIds.get(0), userId);
            }
            return;
        }
        
        // 3. 对于一对多或多对多关系，先删除现有关联，再批量创建新关联
        relationMappingRepository.deleteAllByRelationFieldIdAndSourceRecordId(relationFieldId, sourceRecordId);
        
        List<RelationMapping> relationMappings = new ArrayList<>();
        for (String targetRecordId : targetRecordIds) {
            RelationMapping relationMapping = new RelationMapping();
            relationMapping.setId(IdUtil.createRelationMetaId());
            relationMapping.setRelationFieldId(relationFieldId);
            relationMapping.setSourceRecordId(sourceRecordId);
            relationMapping.setTargetRecordId(targetRecordId);
            relationMappings.add(relationMapping);
        }
        
        relationMappingRepository.saveAll(relationMappings);
    }

    @Override
    @Transactional
    public void deleteRelation(String relationFieldId, String sourceRecordId, String targetRecordId) {
        relationMappingRepository.deleteByRelationFieldIdAndSourceRecordIdAndTargetRecordId(
                relationFieldId, sourceRecordId, targetRecordId);
    }

    @Override
    @Transactional
    public void deleteAllRelations(String relationFieldId, String sourceRecordId) {
        relationMappingRepository.deleteAllByRelationFieldIdAndSourceRecordId(relationFieldId, sourceRecordId);
    }

    @Override
    public List<String> getRelatedRecordIds(String relationFieldId, String sourceRecordId) {
        List<RelationMapping> mappings = relationMappingRepository.findByRelationFieldIdAndSourceRecordId(
                relationFieldId, sourceRecordId);
        
        return mappings.stream()
                .map(RelationMapping::getTargetRecordId)
                .collect(java.util.stream.Collectors.toList());
    }

    @Override
    public Map<String, List<String>> getRelatedRecordsMap(String relationFieldId, List<String> sourceRecordIds) {
        return relationMappingRepository.findTargetRecordIdsByRelationFieldIdAndSourceRecordIds(
                relationFieldId, sourceRecordIds);
    }

    @Override
    public List<String> getSourceRecordIdsByTargetRecordId(String relationFieldId, String targetRecordId) {
        List<RelationMapping> mappings = relationMappingRepository.findByRelationFieldIdAndTargetRecordId(
                relationFieldId, targetRecordId);
        
        return mappings.stream()
                .map(RelationMapping::getSourceRecordId)
                .collect(java.util.stream.Collectors.toList());
    }
}